#include "eval.h"
#include <cstdlib>
#include <ctime>

Eval::Eval() {
    srand(time(0));
    FILE *pf = fopen("info.txt", "r");
    // 共有7种棋子
    char name[10];
    for (int turn = 0; turn < 7; turn++) {
        fscanf(pf, "%s", name);
        PieceInfo & pi = infos[name[0]];
        fscanf(pf, "%d%d", &pi.point, &pi.unitMoveBonus);
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 10; j++) {
                fscanf(pf, "%d", pi.positionBonus[i] + j);
            }
        }
    }
    fclose(pf);
}

Eval::~Eval() {
}

// 按照红色方评估
int Eval::Evaluate(const Board board, const Positions & positions) {
    int ret = 0;
    int general = 0;
    for (const auto & it : positions) {
        int score = GetScore(board, it.second);
        int piece = (it.first & 0xFF);
        if (piece >= 'a') {
            if (piece == 'g') {
                general |= 2;
            }
            ret -= score;
        }
        else {
            if (piece == 'G') {
                general |= 1;
            }
            ret += score;
        }
    }

    static int GAMEOVER = 123456;
    if (general != 3) {
        if (general & 1) {
            return GAMEOVER;
        }
        else {
            return -GAMEOVER;
        }
    }

    return ret;
}

bool InRange(int x, int y) {
    return x >= 0 && x < 9 && y >= 0 && y < 10;
}

bool InRange(const Coordinate & c) {
    return InRange(c.x, c.y);
}

bool IsEnemy(int piece) {
    return (piece & 0xFF) >= 'a';
}

int Eval::GetScore(const Board board, Coordinate c) {
    int ret = 0;

    char piece = (char)(board[c.x][c.y] & 0xFF);
    if (piece >= 'a') {
        piece = piece - 'a' + 'A';
    }
    const PieceInfo & pi = infos[piece];

    ret += pi.point + pi.positionBonus[c.x][c.y];

    static const int DIRX[4] = {1, 0, -1, 0};
    static const int DIRY[4] = {0, -1, 0, 1};

    int tx, ty;
    switch (piece) {
        case 'R': {
            for (int k = 0; k < 4; k++) {
                tx = c.x + DIRX[k];
                ty = c.y + DIRY[k];
                while (InRange(tx, ty)) {
                    if (board[tx][ty]) {
                        if (IsEnemy(board[tx][ty])) {
                            ret += pi.unitMoveBonus;
                        }
                        break;
                    }
                    ret += pi.unitMoveBonus;
                    tx += DIRX[k];
                    ty += DIRY[k];
                }
            }
            break;
        }
        case 'H': {
            for (int abs_dx = 1; abs_dx <= 2; abs_dx++) {
                int abs_dy = 3 - abs_dx;
                for (int s = -1; s <= 1; s += 2) {
                    tx = c.x + abs_dx * s;
                    for (int t = -1; t <= 1; t += 2) {
                        ty = c.y + abs_dy * t;
                        if (!InRange(tx, ty)) {
                            continue;
                        }
                        if (board[c.x + abs_dx / 2 * s][c.y + abs_dy / 2 * t]) {
                            continue;
                        }
                        if (board[tx][ty] && !IsEnemy(board[tx][ty])) {
                            continue;
                        }
                        ret += pi.unitMoveBonus;
                    }
                }
            }
            break;
        }
        case 'E': {
            for (int s = -1; s <= 1; s += 2) {
                tx = c.x + 2 * s;
                for (int t = -1; t <= 1; t += 2) {
                    ty = c.y + 2 * t;
                    if (!InRange(tx, ty) || ty < 5) {
                        continue;
                    }
                    if (board[c.x + s][c.y + t]) {
                        continue;
                    }
                    if (board[tx][ty] && !IsEnemy(board[tx][ty])) {
                        continue;
                    }
                    ret += pi.unitMoveBonus;
                }
            }
            break;
        }
        case 'A': {
            for (int s = -1; s <= 1; s += 2) {
                tx = c.x + s;
                if (tx < 3 || tx > 5) {
                    continue;
                }
                for (int t = -1; t <= 1; t += 2) {
                    ty = c.y + t;
                    if (ty < 7 || ty > 9) {
                        continue;
                    }
                    if (board[tx][ty] && !IsEnemy(board[tx][ty])) {
                        continue;
                    }
                    ret += pi.unitMoveBonus;
                }
            }
            break;
        }
        case 'G': {
            for (int k = 0; k < 4; k++) {
                tx = c.x + DIRX[k];
                ty = c.y + DIRY[k];
                if (tx < 3 || tx > 5 || ty < 7 || ty > 9) {
                    continue;
                }
                if (board[tx][ty] && !IsEnemy(board[tx][ty])) {
                    continue;
                }
                ret += pi.unitMoveBonus;
            }
            break;
        }
        case 'C': {
            for (int k = 0; k < 4; k++) {
                tx = c.x + DIRX[k];
                ty = c.y + DIRY[k];
                while (InRange(tx, ty) && board[tx][ty] == 0) {
                    ret += pi.unitMoveBonus;
                    tx += DIRX[k];
                    ty += DIRY[k];
                }
                do {
                    tx += DIRX[k];
                    ty += DIRY[k];
                } while (InRange(tx, ty) && board[tx][ty] == 0);
                if (InRange(tx, ty) && IsEnemy(board[tx][ty])) {
                    ret += pi.unitMoveBonus;
                }
            }
            break;
        }
        case 'S': {
            tx = c.x;
            ty = c.y - 1;
            if (InRange(tx, ty)) {
                if (board[tx][ty] == 0 || IsEnemy(board[tx][ty])) {
                    ret += pi.unitMoveBonus;
                }
            }
            if (c.y < 5) {
                ty = c.y;
                for (int dx = -1; dx <= 1; dx += 2) {
                    tx = c.x + dx;
                    if (!InRange(tx, ty)) {
                        continue;
                    }
                    if (board[tx][ty] && !IsEnemy(board[tx][ty])) {
                        continue;
                    }
                    ret += pi.unitMoveBonus;
                }
            }
            break;
        }
        default:
            break;
    }

    return ret;
}
